from BaseViewTestCase import BaseViewTestCase
from skillchallenge.game import *
from skillchallenge.models import *
from django.db.models import Q

class GameViewTestCase(BaseViewTestCase):
    
    events = None
    game = None
    
    def setUp(self):
        self.events = []
        self.game = Game()
        for i in range(0,3):
            self.events.append(self.__create_event__(i))
        self.events.append(self.__create_dependent_event__(4))
    
    def __create_event__(self, i):
        actions = []
        actions.append(self.game.code_engine.create_message_action('message ' + str(i)))
        
        precon = []
        precon.append(self.game.code_engine.create_always_fail_precon())
        return self.game.event_engine.add_event(actions = actions, preconditions = precon)
    
    def __create_dependent_event__(self, i):
        actions = []
        actions.append(self.game.code_engine.create_message_action('dependent message ' + str(i)))
        precon = []
        precon.append(self.game.code_engine.create_event_precon(Q(id = self.events[0].id) & Q(timestamp__isnull = False)))
        precon.append(self.game.code_engine.create_event_precon(Q(id = self.events[1].id) & Q(timestamp__isnull = False)))
        precon.append(self.game.code_engine.create_event_precon(Q(id = self.events[2].id) & Q(timestamp__isnull = False)))
        return self.game.event_engine.add_event(actions = actions, preconditions = precon,
                                                player_will = True)
    
    def test_show_messages(self):
        "when i go to game all the messages are showed in the index"
        self.game.fire(self.events[2])
        self.game.tick()
        self.game.fire(self.events[0])
        char = Character.objects.create(name=Name.objects.create(text='char1'), npc=False)
        response = self.client.get('/game/' + str(char.id))
        self.assertTemplateUsed(response, 'skillchallenge/game.html')
        self.assertTrue('event_messages' in response.context[0].dicts[0])
        e = response.context[0].dicts[0]['event_messages']
        self.assertTrue(len(e) == 2)
        self.assertEqual(e[0].text, 'message 2')
        self.assertEqual(e[1].text, 'message 0')
    
    def test_player_will_event_option(self):
        "when the preconditions are met, the player will events should be displayed as options."
        self.game.fire(self.events[2])
        self.game.fire(self.events[0])
        self.game.tick()
        char = Character.objects.create(name=Name.objects.create(text='char1'), npc=False)
        response = self.client.get('/game/' + str(char.id))
        self.assertTrue('options' in response.context[0].dicts[0])
        
        self.assertEqual(0, len(response.context[0].dicts[0]['options']))
        
        self.game.fire(self.events[1])
        response = self.client.get('/game/' + str(char.id))
        self.assertEqual(0, len(response.context[0].dicts[0]['options']))

        self.game.tick()
        response = self.client.get('/game/' + str(char.id))
        self.assertTrue(len(self.__event_options__(self.events[3], response.context[0].dicts[0]['options'])) > 0)
        
    def test_option_chosen(self):
        "the player chose an option"
        self.game.fire(self.events[2])
        self.game.fire(self.events[1])
        self.game.fire(self.events[0])
        self.game.tick()
        char = Character.objects.create(name=Name.objects.create(text='char1'), npc=False)
        response = self.client.get('/game/' + str(char.id) + '/option/' + str(self.events[3].id))
        
        self.assertRedirects(response, '/game/' + str(char.id))
        
        response = self.client.get('/game/' + str(char.id))
        
        self.assertTrue(('dependent message ' + str(self.events[3].id)) in response.content)
        
    def test_location_awareness(self):
        "verify if options are consistent with location"
        init = self.game.location_engine.create_location('initial location', initial = True)
        loc1 = self.game.location_engine.create_location('location 1')
        loc2 = self.game.location_engine.create_location('location 2')
        self.game.location_engine.create_path(init, loc1)
        self.game.location_engine.create_path(loc1, loc2)
        
        self.game.location_engine.move(init, True)
        self.game.location_engine.move(loc2, False)
        
        self.assertEquals(0, len(self.game.player_available()))
        
    def test_put_item(self):
        "try to put an item and see if it shows up"
        init = self.game.location_engine.create_location('initial location', initial = True)
        loc1 = self.game.location_engine.create_location('location 1')
        char = Character.objects.create(name=Name.objects.create(text='char1'), npc=False)
        quest = Quest()
        item1 = quest.item_engine.create_item('item1')
        item2 = quest.item_engine.create_item('item2')
        
        quest.put_item_in(item1, init)
        quest.put_item_in(item2, loc1)
        
        self.game.tick()        
        e = self.game.player_available()
        self.game.player_fire(e[0], None)
        
        response = self.client.get('/game/' + str(char.id))
        self.assertTrue(('you see ' + item1.name) in response.content)
        self.assertContains(response, '<b>inventory:</b> None.', 1)
        pick_is_in = None
        for option in response.context[0].dicts[0]['options']:
            if option.event.info == 'pick:1:1':
                pick_is_in = option.event
                break
            
        self.assertTrue(pick_is_in != None)
        
        self.game.player_fire(pick_is_in, None)
        
        response = self.client.get('/game/' + str(char.id))
        self.assertTrue(('you get ' + item1.name) in response.content) 
        self.assertContains(response, '<b>inventory:</b> ' + item1.name + '.', 1)
        pick_is_in = None
        for option in response.context[0].dicts[0]['options']:
            if option.event.info == 'pick:1:1':
                pick_is_in = option.event
                break
            
        self.assertTrue(pick_is_in == None)
    
    def test_allow_drop_item(self):
        "try to allow a drop of an item and see if the option shows up"
        init = self.game.location_engine.create_location('initial location', initial = True)
        char = Character.objects.create(name=Name.objects.create(text='char1'), npc=False)
        quest = Quest()
        item1 = quest.item_engine.create_item('item1')

        quest.put_item_in(item1, init)        
        quest.allow_drop_in(item1, init)
        
        self.game.tick()  
        e = self.game.player_available()
        self.game.player_fire(e[0], None)      
        e = self.game.player_available()
        self.game.player_fire(e[0], None)
        
        response = self.client.get('/game/' + str(char.id))

        drop_is_in = False
        for option in response.context[0].dicts[0]['options']:
            if option.event.info == 'drop:1:1':
                drop_is_in = True
                break
            
        self.assertTrue(drop_is_in)
        
    def test_put_a_NPC(self):
        "try to put a NPC and see if it shows up"
        init = self.game.location_engine.create_location('initial location', initial = True)
        char = Character.objects.create(name=Name.objects.create(text='char1'), npc=False)
        quest = Quest()
        npc1 = quest.npc_engine.create_npc('npc1')
        
        self.game.fire(quest.put_npc_in(npc1, init))
        
        self.game.tick()        
        e = self.game.player_available()
        self.game.player_fire(e[0], None)
        
        response = self.client.get('/game/' + str(char.id))
        self.assertTrue(('you see ' + npc1.name.text) in response.content)
        
    def test_move_a_NPC(self):
        "try to move a NPC and see if it shows off"
        init = self.game.location_engine.create_location('initial location', initial = True)
        location1 = self.game.location_engine.create_location('location 1')
        self.game.location_engine.create_path(init, location1)
        self.game.location_engine.create_path(location1, init)
        
        char = Character.objects.create(name=Name.objects.create(text='char1'), npc=False)
        
        quest = Quest()
        npc1 = quest.npc_engine.create_npc('npc1')
        
        e = quest.put_npc_in(npc1, init)
        self.game.fire(e)
        
        self.game.tick()        
        e = self.game.player_available()
        self.game.player_fire(e[0], None)
        
        response = self.client.get('/game/' + str(char.id))
        self.assertContains(response, 'you see ' + npc1.name.text + '.', 1)
        
        event = quest.move_npc(npc1, location1)
        self.game.fire(event)
        
        response = self.client.get('/game/' + str(char.id))
        self.assertContains(response, 'you see ' + npc1.name.text + ' moving to ' + location1.name + '.', 1)
        
        self.game.player_fire(self.game.player_available()[0], None)
        response = self.client.get('/game/' + str(char.id))
        self.assertContains(response, 'you see ' + npc1.name.text + '.', 2)
        
        self.game.player_fire(self.game.player_available()[0], None)
        response = self.client.get('/game/' + str(char.id))
        self.assertContains(response, 'you see ' + npc1.name.text + '.', 2)
        
    def test_talk_with_NPC(self):
        "try to initiate a chat with a npc"
        init = self.game.location_engine.create_location('initial location', initial = True)
        location1 = self.game.location_engine.create_location('location 1')
        self.game.location_engine.create_path(init, location1)
        self.game.location_engine.create_path(location1, init)

        char = Character.objects.create(name=Name.objects.create(text='char1'), npc=False)
        
        quest = Quest()
        npc1 = quest.npc_engine.create_npc('npc1')
        
        self.game.fire(quest.put_npc_in(npc1, init))
        
        speech = quest.begin_chat(char, npc1, 'chat 1')
        speech.text = "hey what's up?"
        speech.reply = "are you mad?"
        speech.save()
        
        branch1 = quest.end_branch_chat(speech)
        branch1.text = "yes."
        branch1.reply = "no kidding!"
        branch1.save()
        
        branch2 = quest.branch_chat(speech)
        branch2.text = "no."
        branch2.reply = "no joking!"
        branch2.branches.add(speech)
        branch2.save()
        
        branch3 = quest.end_branch_chat(speech)
        branch3.text = "maybe."
        branch3.reply = "no way!"
        branch3.save()
        
        quest.begin_event(speech)
              
        self.game.tick()        
        e = self.game.player_available()
        
        self.game.player_fire(e[0], char)
        
        response = self.client.get('/game/' + str(char.id))
        self.assertTrue(('you see ' + npc1.name.text) in response.content)        
        self.assertTrue(('say to ' + npc1.name.text + ': &quot;hey what&#39;s up?&quot;') in response.content)

        e = self.game.player_available()
        self.game.player_fire(e[0], char)
        
        response = self.client.get('/game/' + str(char.id))
        self.assertTrue(('say to ' + npc1.name.text + ': &quot;hey what&#39;s up?&quot;') not in response.content)
        
        e = self.game.player_available()
        self.game.player_fire(e[0], char)
        
        response = self.client.get('/game/' + str(char.id))
        e = self.game.player_available()
        self.game.player_fire([event for event in e if 'CHAT' in event.info][0], char)
        
        response = self.client.get('/game/' + str(char.id))
        self.assertTrue([event for event in e if 'move' in event.info][0] not in [opt.event for opt in response.context[0]['options']])
        
        e = self.game.player_available()
        self.game.player_fire([event for event in e if 'CHAT:' in event.info][0], char)
        
        response = self.client.get('/game/' + str(char.id))
        self.assertTrue(len([opt for opt in response.context[0]['options'] if opt.event.info.startswith('CHAT_BEGIN')]) > 0)
        self.assertTrue(len([opt for opt in response.context[0]['options'] if (not opt.event.info.startswith('CHAT_BEGIN')) and (not opt.event.info.startswith('CHAT_INTERRUPT'))]) == 0)
        
        e = self.game.player_available()
        self.game.player_fire([event for event in e if 'CHAT_BEGIN' in event.info][0], char)
        
        response = self.client.get('/game/' + str(char.id))
        self.assertTrue(len([opt for opt in response.context[0]['options'] if opt.event.info.startswith('CHAT_BEGIN')]) == 0)
        self.assertTrue(len([opt for opt in response.context[0]['options'] if opt.event.info.startswith('CHAT:')]) == 1)
        self.assertTrue(len([opt for opt in response.context[0]['options'] if opt.event.info.startswith('CHAT_END')]) == 2)
        
        e = self.game.player_available()
        self.game.player_fire([event for event in e if 'CHAT_END:' in event.info][0], char)
        
        response = self.client.get('/game/' + str(char.id))
        self.assertTrue(len(response.context[0]['options']) == 1)
        self.assertTrue(len([opt for opt in response.context[0]['options'] if opt.event.info.startswith('move')]) == 1)
        
    def test_interrupt_talk_with_NPC(self):
        "try to interrupt a chat with a npc"
        init = self.game.location_engine.create_location('initial location', initial = True)
        location1 = self.game.location_engine.create_location('location 1')
        self.game.location_engine.create_path(init, location1)
        
        char = Character.objects.create(name=Name.objects.create(text='char1'), npc=False)
        
        quest = Quest()
        npc1 = quest.npc_engine.create_npc('npc1')
        
        self.game.fire(quest.put_npc_in(npc1, init))
        
        speech = quest.begin_chat(char, npc1, 'chat 1')
        speech.text = "hey what's up?"
        speech.reply = "are you mad?"
        speech.save()
        quest.begin_event(speech)
              
        self.game.tick()        
        e = self.game.player_available()
        self.game.player_fire(e[0], char)
        
        e = self.game.player_available()
        self.game.player_fire([event for event in e if 'CHAT' in event.info][0], char)
        
        response = self.client.get('/game/' + str(char.id))
        self.assertTrue(len(response.context[0]['options']) == 1)
        self.assertTrue(len([opt for opt in response.context[0]['options'] if opt.event.info.startswith('CHAT_INTERRUPT')]) == 1)
        
        self.game.player_fire(self.game.player_available()[0], char)
        response = self.client.get('/game/' + str(char.id))
        self.assertTrue(len(response.context[0]['options']) == 1)
        self.assertTrue(len([opt for opt in response.context[0]['options'] if opt.event.info.startswith('move')]) == 1)

    def test_chaty_events(self):
        "test events that should be available when chatting"
        init = self.game.location_engine.create_location('initial location', initial = True)
        location1 = self.game.location_engine.create_location('location 1')
        self.game.location_engine.create_path(init, location1)
        
        item = Item.objects.create(name='item 1')
        
        char = Character.objects.create(name=Name.objects.create(text='char1'), npc=False)
        
        quest = Quest()
        npc1 = quest.npc_engine.create_npc('npc1')
        
        self.game.fire(quest.put_npc_in(npc1, init))
        
        speech = quest.begin_chat(char, npc1, 'chat 1')
        speech.text = "hey what's up?"
        speech.reply = "are you mad?"
        speech.save()
                
        receive_event = quest.give_item(item, npc1, char)
        give_event = quest.give_item(item, char, npc1)
        give_event.chatting = True
        give_event.save()
        quest.chain(receive_event, give_event) 

        quest.trigger(quest.begin_event(speech), receive_event)
              
        self.game.tick()        
        e = self.game.player_available()
        self.game.player_fire(e[0], char)
        e = self.game.player_available()
        self.game.player_fire([event for event in e if 'CHAT' in event.info][0], char)
        
        response = self.client.get('/game/' + str(char.id))
        
        self.assertTrue('you receive item 1 from npc1.' in response.content)
        self.assertTrue(give_event in self.game.player_available())
        